/*
 * File     : internal_platform_callback_AbstractThunkManagerDelegate.c
 * Created  : 07 Jan 2012
 *
 * Copyright © 2012 Matthew Wilson (mj. {my-surname} .uk {at} gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "common.h"

typedef struct
{
    JavaVM* javaVM;
    jclass implType;
    jmethodID method;
    jobject delegate;
} callback_info;

/*
 * Class:     com_googlecode_dni_internal_callback_AbstractThunkManagerDelegate
 * Method:    getEntrySize
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_googlecode_dni_internal_callback_AbstractThunkManagerDelegate_getEntrySize(
    JNIEnv* env,
    jclass clazz )
{
    return (jint) sizeof( callback_info );
}

/*
 * Class:     com_googlecode_dni_internal_callback_AbstractThunkManagerDelegate
 * Method:    fillEntry
 * Signature: (JLjava/lang/Class;Ljava/lang/reflect/Method;Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL Java_com_googlecode_dni_internal_callback_AbstractThunkManagerDelegate_fillEntry(
    JNIEnv* env,
    jclass clazz,
    jlong infoAddress,
    jclass implType,
    jobject method,
    jobject delegate )
{
    callback_info* info = (callback_info*) JLONG_TO_POINTER( infoAddress );
    (*env)->GetJavaVM( env, &info->javaVM ); 
    info->implType = (*env)->NewGlobalRef( env, implType );
    info->method   = (*env)->FromReflectedMethod( env, method );
    info->delegate = (*env)->NewGlobalRef( env, delegate );
}

/*
 * Class:     com_googlecode_dni_internal_callback_AbstractThunkManagerDelegate
 * Method:    clearEntryImpl
 * Signature: (JLjava/lang/Object;)I
 */
JNIEXPORT jint JNICALL Java_com_googlecode_dni_internal_callback_AbstractThunkManagerDelegate_clearEntryImpl(
    JNIEnv* env,
    jclass clazz,
    jlong infoAddress,
    jobject delegate )
{
    callback_info* info = (callback_info*) JLONG_TO_POINTER( infoAddress );
    jint result = 0;
    JavaVM* javaVM;
    
    (*env)->GetJavaVM( env, &javaVM );
    if ( info->javaVM != javaVM )
    {
        result |= 1;
    }
    info->javaVM   = NULL;
    
    if ( (*env)->GetObjectRefType( env, info->implType ) == JNIGlobalRefType )
    {
       (*env)->DeleteGlobalRef( env, info->implType );
    }
    else
    {
        result |= 2;
    }
    info->implType = NULL;
    
    // no check on method so far    
    info->method   = NULL;
    
    if ( (*env)->GetObjectRefType( env, info->delegate ) == JNIGlobalRefType )
    {
       (*env)->DeleteGlobalRef( env, info->delegate );
       if ( !(*env)->IsSameObject( env, delegate, info->delegate ) )
       {
        result |= 16;
       }
    }
    else
    {
        result |= 8;
    }
    info->delegate = NULL;
    
    return result;
}
